﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenTK;
using OpenTK.Graphics.OpenGL4;
using OpenTK.Input;
using System.Drawing;
using OpenTK.Graphics;
using Common;

namespace T12_NormalMapping {
    class T13_NormalMappingGameWindow : GameWindow {
        public T13_NormalMappingGameWindow() {
            this.Load += T13_NormalMappingGameWindow_Load;
            this.Resize += T13_NormalMappingGameWindow_Resize;
            this.RenderFrame += T13_NormalMappingGameWindow_RenderFrame;
            this.Unload += T13_NormalMappingGameWindow_Unload;
            this.Width = 1024;
            this.Height = 768;
            this.Title = "T12_NormalMappingGameWindow";

        }


        private void T13_NormalMappingGameWindow_RenderFrame(object sender, FrameEventArgs e) {
            GL.ClearColor(0.0f, 0.0f, 0.4f, 0.0f);
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

            Render();

            SwapBuffers();
            ProcessEvents();
        }

        Shader shader;
        Vao vao;
        ModelMesh mesh ;
        Texture2D diffuseTexture, normalTexture, specularTexture;
        Vbo<Vector3> vertexBuffer, normalBuffer, tangentBuffer, bitangentBuffer;
        Vbo<Vector2> uvBuffer;
        Vbo<ushort> indexBuffer;
        VertexAttribManager attribs = new VertexAttribManager();
        private void T13_NormalMappingGameWindow_Load(object sender, EventArgs e) {

            VSync = VSyncMode.Off;
            GL.Enable(EnableCap.DepthTest);
            GL.DepthFunc(DepthFunction.Less);
            GL.Enable(EnableCap.CullFace);

            vao = new Vao();
            shader = new Shader("shader.vs","shader.fs");
            diffuseTexture = Texture2D.Load("diffuse.dds");
            normalTexture = Texture2D.Load("normal.bmp");
            specularTexture = Texture2D.Load("specular.dds");

            mesh = MeshLoader.LoadObjIndexedTBN("cylinder.obj");
            createBuffers(mesh);

            attribs.AddAttrib(3, vertexBuffer);
            attribs.AddAttrib(2, uvBuffer);
            attribs.AddAttrib(3, normalBuffer);
            attribs.AddAttrib(3, tangentBuffer);
            attribs.AddAttrib(3, bitangentBuffer);
        }

        private void createBuffers(ModelMesh mesh) {
            vertexBuffer = new Vbo<Vector3>(mesh.Vertices);
            uvBuffer = new Vbo<Vector2>(mesh.Uvs);
            normalBuffer = new Vbo<Vector3>(mesh.Normals);
            tangentBuffer = new Vbo<Vector3>(mesh.Tangents);
            bitangentBuffer = new Vbo<Vector3>(mesh.BiTangents);
            indexBuffer = new Vbo<ushort>( BufferTarget.ElementArrayBuffer, BufferUsageHint.StaticDraw,mesh.Indices);
        }

        private void Render() {
            shader.Use();
            InputControls.computeMatricesFromInput(this);
            FpsCounter.CountFps();

            var model = Matrix4.Identity;
            var mvp = model*InputControls.ViewMatrix * InputControls.ProjectionMatrix;
            var mv = model * InputControls.ViewMatrix;
            var mv3x3 = new Matrix3(mv);
            shader.SetMatrix4("M", ref model);
            shader.SetMatrix4("V", ref InputControls.ViewMatrix);
            shader.SetMatrix4("MVP", ref mvp);
            shader.SetMatrix3("MV3x3",ref mv3x3);

            Vector3 lightPos = new Vector3(0, 0, 4);
            shader.SetVector3("LightPosition_worldspace", lightPos);

            diffuseTexture.Active(TextureUnit.Texture0, shader, "DiffuseTextureSampler");
            normalTexture.Active(TextureUnit.Texture1, shader, "NormalTextureSampler");
            specularTexture.Active(TextureUnit.Texture2, shader, "SpecularTextureSampler");

            attribs.Enable();
            indexBuffer.Bind();
            GL.DrawElements(BeginMode.Triangles, mesh.Indices.Length, DrawElementsType.UnsignedShort, 0);
            attribs.Disable();

        }

        private void T13_NormalMappingGameWindow_Resize(object sender, EventArgs e) {
            GL.Viewport(0, 0, Width, Height);
        }



        private void T13_NormalMappingGameWindow_Unload(object sender, EventArgs e) {
            //GlDisposableObjectBase.DisposeObjects(shader, vao, diffuseTexture, normalTexture, specularTexture,vertexBuffer,normalBuffer,
            //    uvBuffer,tangentBuffer,bitangentBuffer,indexBuffer,mesh);
            GlDisposableObjectBase.DisposeAllDisposableMembers(this);
        }

    }
}
